package org.lyq.erp.config.login;

import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.lyq.erp.auth.employee.pojo.Employee;
import org.lyq.erp.auth.employee.service.EmployeeService;
import org.lyq.erp.auth.menu.pojo.Menu;
import org.lyq.erp.auth.menu.service.MenuService;
import org.lyq.erp.auth.resources.pojo.Resources;
import org.lyq.erp.auth.resources.service.ResourcesService;
import org.lyq.erp.config.constant.ConfigConstant;
import org.lyq.erp.config.redis.RedisUtils;
import org.lyq.erp.utils.string.MD5;
import org.lyq.erp.utils.string.ObjectEmptyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 
 * @ClassName: LoginController
 * @Description: (登陆系统控制类)
 * @author LYQ
 * @date 2019年5月31日
 *
 */
@Controller
@PropertySource(value = { "classpath:application.properties" }) // 加载配置文件
public class LoginController {

	private static Logger logger = LoggerFactory.getLogger(LoginController.class);

	@Value("${check_code}")
	private String check_code;

	@Resource
	private MenuService menuService;

	@Resource
	private EmployeeService employeeService;

	@Resource
	private ResourcesService resourcesService;

	@Resource
	private RedisUtils redisUtils;

	@Resource
	private RedisTemplate<String, String> redisTemplate;

	// private static int captchaExpires = 3 * 60; // 超时时间3min

	/**
	 * 
	 * @Title: register @Description: (跳转到注册页面) @param @return 参数 @return String
	 *         返回类型 @throws
	 */
	@RequestMapping("/register")
	public String register() {

		return "register";
	}

	@RequestMapping("/index")
	public String index() {

		return "index";
	}

	/**
	 * 
	 * @Title: login @Description: (跳转到用户登录) @param @param str @param @param
	 *         map @param @param request @param @return 参数 @return String
	 *         返回类型 @throws
	 */
	@RequestMapping("/login")
	public String login(String str, ModelMap map, HttpServletRequest request) {

		Employee emp = (Employee) request.getSession().getAttribute(ConfigConstant.USER_LOGIN);
		if (emp != null) {
			return "index";
		}
		// 判定cookie中是否存储了用户信息，将用户账号回显出去
		Cookie cookie = getCookie(request.getCookies(), ConfigConstant.COOKIE_USERNAME_AND_PASSWORD);
		if (cookie != null && ObjectEmptyUtils.isNotEmptyString(cookie.getValue())) {
			String[] strs = cookie.getValue().split(ConfigConstant.USER_SPLIT);
			if (strs != null && strs.length == 3) {
				map.put("username", strs[0]);
				map.put("password", strs[1]);
				map.put("remember", strs[2]);
			}
		}
		return "login";
	}

	/**
	 * 
	 * @Title: registerSubmit @Description: (用户激活账号) @param @param
	 *         employee @param @param checkcode @param @param request @param @param
	 *         response @param @param map @param @return 参数 @return String
	 *         返回类型 @throws
	 */
	@RequestMapping("/registerSubmit")
	public String registerSubmit(Employee employee, String checkcode, HttpServletRequest request,
			HttpServletResponse response, ModelMap map) {

		try {

			if (!registerValidation(employee, checkcode, request, response)) {
				map.put(ConfigConstant.DATA_BEAN, employee);
				return "register";
			}
			// 删除cookie中的值
			deleteCookie(ConfigConstant.CAPTCHACODE_UUID, response);
			// 设置员工的属性
			employee.setEmpPassword(MD5.GetMD5Code(employee.getEmpPassword()));
			// 设置状态属性2为该用户的激活状态
			employee.setStatus(2);
			// 设置登录是的ip
			employee.setEmpLoginip(getUserIp(request));

			employeeService.updateByPrimaryKeySelective(employee);

		} catch (Exception e) {
			logger.info(e.getMessage());
			employee.addErrorMessage("register008");
			map.put(ConfigConstant.DATA_BEAN, employee);
			return "register";
		}

		return "login";
	}

	/**
	 * 
	 * @Title: loginSubmit @Description: (用户登录，登录后跳转index界面) @param request @param
	 *         response @param username @param password @param remember @param
	 *         modelmap @param checkcode @param 参数 @return String 返回类型 @throws
	 */
	@RequestMapping("/loginSubmit")
	public String loginSubmit(HttpServletRequest request, HttpServletResponse response, Employee emp, String remember,
			ModelMap map, String checkcode) {

		// 获取一个session域对象
		HttpSession session = request.getSession();
		map.put("remember", remember);

		if (session.getAttribute(ConfigConstant.USER_LOGIN) != null)
			return "index";

		if (!loginValidation(emp, checkcode, session, request, response)) {
			map.put(ConfigConstant.DATA_BEAN, emp);
			return "login";
		}

		// 检验过了以后，可以根据用户名获取一个用户信息
		Employee employee = employeeService.selectEmployeeByUsername(emp.getEmpUsername());
		if (employee != null && employee.getEmpUuid() != null) {

			// 设置redis中用户登录状态的值
			redisUtils.set("userSeesion:" + employee.getEmpUuid() + "", ConfigConstant.STATUS_ID_1);

			// 获取个人拥有的所有资源
			String allResources = getAllResources(employee.getEmpUuid());
			session.setAttribute(ConfigConstant.MY_ALL_RES, allResources);

			// 查询个人拥有的所有菜单
			List<Menu> allMenus = getAllMenus(employee.getEmpUuid());
			session.setAttribute(ConfigConstant.ALL_MENUS_LIST, allMenus);

			// 修改员工表中的信息
			employee.setEmpLastlogintime(System.currentTimeMillis());
			employee.setEmpLoginip(getUserIp(request));
			employeeService.updateByPrimaryKeySelective(employee);

			if (remember != null) {

				// 登录成功后判定是否记住密码 ,将用户名和密码存入到cookie中
				String usernameAndPassword = employee.getEmpUsername() + ConfigConstant.USER_SPLIT
						+ employee.getEmpPassword() + ConfigConstant.USER_SPLIT + "1";
				addCookie(ConfigConstant.COOKIE_USERNAME_AND_PASSWORD, usernameAndPassword, response);
			}

			session.setAttribute(ConfigConstant.USER_LOGIN, employee);
			// 成功登录后将session中的错误次数删除
			session.removeAttribute(ConfigConstant.ERROR_COUNT);

			return "index";
		} else {
			emp.addErrorMessage("empUsername", "login006", "登陆失败");
			map.put(ConfigConstant.DATA_BEAN, emp);
			return "login";
		}

	}

	/**
	 * 用户登出
	 * 
	 * @param request
	 * @return
	 */
	@RequestMapping("/logOut")
	public String logOut(HttpServletRequest request) {
		request.getSession().invalidate();
		return "login";
	}

	/**
	 * 
	 * @Title: registerValidation @Description: (校验用户激活的提交信息) @param @param
	 *         employee @param @param checkcode @param @param request @param @param
	 *         response @param @return 参数 @return boolean 返回类型 @throws
	 */
	private boolean registerValidation(Employee employee, String checkcode, HttpServletRequest request,
			HttpServletResponse response) {

		if (ObjectEmptyUtils.isEmptyString(checkcode)) {
			employee.addErrorMessage("checkcode", "register001", "请输入验证码");
		} else {
			if (!equalCheckCode(request.getCookies(), checkcode, response)) {
				employee.addErrorMessage("checkcode", "register002", "验证码有误");
			}
		}
		if (ObjectEmptyUtils.isEmptyString(employee.getEmpName())) {
			employee.addErrorMessage("empName", "register003", "请输入姓名");
		}
		if (ObjectEmptyUtils.isEmptyString(employee.getEmpIdcard())) {
			employee.addErrorMessage("empIdcard", "register004", "请输入有效身份证");
		}

		if (ObjectEmptyUtils.isNotEmptyString(employee.getEmpIdcard())
				&& ObjectEmptyUtils.isNotEmptyString(employee.getEmpName())) {
			Employee emp = employeeService.getEmpUsernameByEmpNameAndEmpIdcard(employee);
			if (!ObjectEmptyUtils.isNotEmpty(emp)) {
				employee.addErrorMessage("empName", "register005", "姓名或有效身份证输入有误");
			} else {
				if (ObjectEmptyUtils.isNotEmpty(emp.getStatus()) && !"1".equals(emp.getStatus())) {
					employee.addErrorMessage("username", "register006", "该用户已经被激活，无需再次激活");
				}
			}
		}
		if (ObjectEmptyUtils.isEmptyString(employee.getEmpPassword()) || employee.getEmpPassword().trim().length() < 6
				|| employee.getEmpPassword().trim().length() > 18) {
			employee.addErrorMessage("empPassword", "register007", "密码长度必须在6到18之间");
		}

		return employee.getMap().isEmpty() ? true : false;
	}

	/**
	 * @param response
	 * @Title: loginValidation @Description: (登陆信息校验，校验内容用户名，密码，登陆错误次数，异地登陆) @param
	 *         request @param @param emp 登陆信息 @param @param checkcode
	 *         验证码 @param @param session 参数 @return void 返回类型 @throws
	 */
	private boolean loginValidation(Employee emp, String checkcode, HttpSession session, HttpServletRequest request,
			HttpServletResponse response) {

		Integer errorCount = 0;

		if (emp != null) {

			if (ObjectEmptyUtils.isEmptyString(emp.getEmpUsername())
					|| ObjectEmptyUtils.isEmptyString(emp.getEmpPassword())) {

				if (ObjectEmptyUtils.isEmptyString(emp.getEmpUsername())) {
					emp.addErrorMessage("empUsername", "login001", "登陆用户不能为空");
				}
				if (ObjectEmptyUtils.isEmptyString(emp.getEmpPassword())) {
					emp.addErrorMessage("empPassword", "login002", "密码不能为空");
				}
			} else {

				// 先确定是否需要验证登陆
				errorCount = (Integer) session.getAttribute(ConfigConstant.ERROR_COUNT);
				if (errorCount != null && errorCount >= ConfigConstant.MAX_ERROR_COUNT
						&& session.getAttribute(ConfigConstant.LONG_DISTANCE_LANDING) == null) {
					if (ObjectEmptyUtils.isNotEmptyString(checkcode)) {
						boolean flag = equalCheckCode(request.getCookies(), checkcode, response);
						if (!flag) {
							emp.addErrorMessage("checkcode", "register002", "验证码有误");
						}
					} else {
						emp.addErrorMessage("checkcode", "login004", "登陆错误次数过多，请输入验证码登陆");
					}
				}

				Employee employee = employeeService.selectEmployeeByUsername(emp.getEmpUsername());
				if (employee == null) {
					emp.addErrorMessage("empUsername", "login003", "登陆用户名错误");
				} else {
					// 判定密码是否正确
					if (!MD5.GetMD5Code(emp.getEmpPassword()).equals(employee.getEmpPassword())) {
						emp.addErrorMessage("empPassword", "login005", "密码输入错误");
					}
					// 判定是否是异地登陆
					if (ObjectEmptyUtils.isEmptyString(getUserIp(request))
							|| !getUserIp(request).equals(employee.getEmpLoginip())) {
						if (ObjectEmptyUtils.isNotEmptyString(checkcode)) {
							boolean flag = equalCheckCode(request.getCookies(), checkcode, response);
							if (!flag) {
								setSessionErrorCount(session, ConfigConstant.ERROR_COUNT, 4);
								emp.addErrorMessage("checkcode", "register002", "验证码有误");
							} else {
								session.removeAttribute(ConfigConstant.LONG_DISTANCE_LANDING);
							}
						} else {
							session.setAttribute(ConfigConstant.LONG_DISTANCE_LANDING,
									ConfigConstant.LONG_DISTANCE_LANDING);
							setSessionErrorCount(session, ConfigConstant.ERROR_COUNT, 3);
							emp.addErrorMessage("checkcode", "login007", "您在异地登陆，请输入验证码登陆");
						}
					}
				}
			}
		}

		if (!emp.getMap().isEmpty()) {
			setSessionErrorCount(session, ConfigConstant.ERROR_COUNT);
		}
		return emp.getMap().isEmpty() ? true : false;
	}

	/**
	 * 
	 * @Title: equalCheckCode @Description: (判断验证是否输入正确) @param @param
	 *         cookies @param @param checkcode @param @param response @param @return
	 *         参数 @return boolean 返回类型 @throws
	 */
	private boolean equalCheckCode(Cookie[] cookies, String checkcode, HttpServletResponse response) {

		if (cookies != null && ObjectEmptyUtils.isNotEmptyString(checkcode)) {
			for (Cookie cookie : cookies) {
				if (ConfigConstant.CAPTCHACODE_UUID.equals(cookie.getName())) {

					if (ObjectEmptyUtils.isNotEmptyString(cookie.getValue())) {

						String redisCheckCode = (String) redisUtils.get(cookie.getValue());
						// 清除redis中的验证码
						redisUtils.remove(cookie.getValue());
						if (checkcode.equalsIgnoreCase(redisCheckCode)) {
							deleteCookie(ConfigConstant.CAPTCHACODE_UUID, response);
							return true;
						}

					}
				}
			}
		}
		return false;
	}

	/**
	 * 
	 * @Title: getCookie @Description: (获取指定的cookie对象) @param @param
	 *         cookies @param @param cookieName @param @return 参数 @return Cookie
	 *         返回类型 @throws
	 */
	private Cookie getCookie(Cookie[] cookies, String cookieName) {

		if (cookies != null && ObjectEmptyUtils.isNotEmptyString(cookieName)) {
			for (Cookie cookie : cookies) {
				if (cookieName.equals(cookie.getName())) {
					return cookie;
				}
			}
		}
		return null;
	}

	/**
	 * 
	 * @Title: deleteCookie @Description: (清空指定name值cookie的value值) @param @param
	 *         key @param @param response 参数 @return void 返回类型 @throws
	 */
	private void deleteCookie(String key, HttpServletResponse response) {

		Cookie cookie = new Cookie(key, null);
		cookie.setMaxAge(0);
		response.addCookie(cookie);
	}

	/**
	 * 
	 * @Title: addCookie @Description: (添加一个cookie) @param @param
	 *         cookieName @param @param cookieValue @param @param response
	 *         参数 @return void 返回类型 @throws
	 */
	private void addCookie(String cookieName, String cookieValue, HttpServletResponse response) {

		@SuppressWarnings("deprecation")
		Cookie cookie = new Cookie(cookieName, URLDecoder.decode(cookieValue));
		// 设置最长的时间
		cookie.setMaxAge(Integer.MAX_VALUE);
		// 设置cookie的类别
		cookie.setPath("/");

		response.addCookie(cookie);
	}

	/**
	 * 
	 * @Title: setSessionErrorCount @Description: (设置登录错误的次数) @param @param
	 *         session @param @param errorCount 参数 @return void 返回类型 @throws
	 */
	private void setSessionErrorCount(HttpSession session, String errorCount) {

		if (ObjectEmptyUtils.isNotEmpty(check_code) && ConfigConstant.STATUS_ID_1.equals(check_code)) {
			if (session != null && session.getAttribute(errorCount) != null) {

				Integer count = (Integer) session.getAttribute(errorCount);
				session.setAttribute(errorCount, ++count);
			} else {
				session.setAttribute(errorCount, 1);
			}
		}

	}

	private void setSessionErrorCount(HttpSession session, String errorCount, int i) {
		if (ObjectEmptyUtils.isNotEmpty(check_code) && ConfigConstant.STATUS_ID_1.equals(check_code)) {
			if (session != null && session.getAttribute(errorCount) != null) {
				session.setAttribute(errorCount, i);
			} else {
				session.setAttribute(errorCount, i);
			}
		}
	}

	/**
	 * 
	 * @Title: getUserIp @Description:(获取登录人的ip地址) @param @param
	 *         request @param @return 参数 @return String 返回类型 @throws
	 */
	private String getUserIp(HttpServletRequest request) {
		// 获取激活请求客服端ip
		String loginIp = request.getHeader("x-forwarded-for");
		if (loginIp == null || loginIp.length() == 0 || "unknown".equalsIgnoreCase(loginIp)) {
			loginIp = request.getHeader("Proxy-Client-IP");
		}
		if (loginIp == null || loginIp.length() == 0 || "unknown".equalsIgnoreCase(loginIp)) {
			loginIp = request.getHeader("WL-Proxy-Client-IP");
		}
		if (loginIp == null || loginIp.length() == 0 || "unknown".equalsIgnoreCase(loginIp)) {
			loginIp = request.getRemoteAddr();
		}
		return loginIp;
	}

	private String getAllResources(Integer empUuid) {
		// 查询个人的所有资源
		List<Resources> myAllRes = resourcesService.selectMyAllResources(empUuid);
		// 判定myAllRes集合是否为空
		if (!ObjectEmptyUtils.isEmptyList(myAllRes)) {

			StringBuilder sb = new StringBuilder();
			for (Resources resources : myAllRes) {
				sb.append(resources.getResUrl()).append(",");
			}
			return sb.toString();
		}
		return "";
	}

	private List<Menu> getAllMenus(Integer empUuid) {

		// 查询个人的所有菜单
		Map<String, Integer> map = new HashMap<String, Integer>();
		map.put("empUuid", empUuid);
		map.put("menuUuid", 1);

		// 登录之后获取个人拥有的菜单 （存入到session中）
		List<Menu> mList = menuService.selectMenuByEmpUuid(map);
		if (mList != null) {
			for (Menu menu : mList) {
				map.put("menuUuid", menu.getMenuUuid());
				List<Menu> mpList = menuService.selectMenuByEmpUuid(map);
				menu.setMpList(mpList);
			}
		}

		return mList;
	}

}
